import trigger from '../../effect/trigger.js'
import { TriggerOpTypes, hasChanged } from '../../utils.js'

export default function (target, key, value) {
  // 拦截到 set 操作后，要做一些额外的事情，要做的事情，叫做派发更新

  // 具体的操作类型还需要进一步判断，有可能是设置，有可能是新增
  const type = target.hasOwnProperty(key)
    ? TriggerOpTypes.SET
    : TriggerOpTypes.ADD

  // 假如值没有变化，不需要派发更行
  const oldValue = target[key] // 获取旧值
  // 先缓存一下旧的数组长度
  const oldLen = Array.isArray(target) ? target.length : undefined

  // 先进行设置操作，在这一步设置完值的时候，如果是数组，length 属性可能也会改变
  const result = Reflect.set(target, key, value)

  // 是否需要派发更新需要进行判断
  if (hasChanged(oldValue, value)) {
    // 派发更新
    trigger(target, type, key)

    // 有些情况，length 属性会隐式的发生变化
    // 需要判断 length 是否有变化，如果有变化，需要对 length 惊醒派发更新
    if (Array.isArray(target) && oldLen !== target.length) {
      // 之所以这里判断一下，是因为 length 显示的改变是会触发派发更新
      if (key !== 'length') {
        // 进入这个 if，说明 length 发生了隐式的变化，需要手动派发更新
        trigger(target, TriggerOpTypes.SET, 'length')
      } else {
        // 进入此 else，说明 length 发生了显示的改变
        // 需要处理新的长度小于旧的长度的情况，因为这里涉及到删除的操作
        for (let i = target.length; i < oldLen; i++) {
          // 手动触发删除派发更新
          trigger(target, TriggerOpTypes.DELETE, i.toString())
        }
      }
    }
  }

  return result
}
